/** Part of Zombie Navigator
	Copyright © 2016  Zombie Navigator Developers
	
	@file
	@module
	@license AGPL-3.0+
	
*/ 'use strict';


/* Used modules */
const _pMeta = require('./meta');
const _pUiFactory = require('./ui-factory');

/*
	Clarification: Zombie windows = Browser tabs
	A Zombie script can have one Browser window for each window type it is
	allowed to open, which hosts all the script's Zombie windows of that type.
*/

const _monitorPath = 'ui/monitor.html';
const _monitorScriptPath = 'ui/monitor.js';


/* Internal APIs */
const CLASS_NON_PRIVATE = Symbol(); // Non-private resources
const CLASS_PRIVATE = Symbol(); // Private resources

/** @public */
const createControlGroup = (controllerURI, policies) => {
	const messageSenders = [], quitHandlers = [], windowClosers = [];
	
	/*
		When the monitor tab is closed all the hosted scripted tabs should be
		closed and the script should be terminated.
		
		Window deduplicating in a PB-enforced browser is not implemented
		in which case both the "non-private" window and the private window are
		actually PB-enabled but seperately managed.
	*/
	const _openBrowserWindow = (isPrivate) => {
		const pUiFactory = _pUiFactory, pMeta = _pMeta;
		
		return new Promise((resolve, reject) => {
			pUiFactory.openPopup(pMeta.getURIFromDataPath(_monitorPath)
				,!!isPrivate
				,pMeta.getURIFromDataPath(_monitorScriptPath)
				,{
					quitSession () {
						quitHandlers.forEach(f => f());
						quitHandlers.length = 0;
					}
				})
			.then(t => {try {
				windowClosers.push(() => {
					t.tabs.closeAllTabs();
				});
				
				t.tabs.addEventListener((type, data) =>
					void(messageSenders.forEach(f => f(type, data))));
				
				t.onClose(() => void(quitHandlers.forEach(f => f())
					,quitHandlers.length = 0));
				
				messageSenders.push((type, data) =>
					void(t.sendMessage({__proto__: null
						,type: type + ''
						,isPrivate: t.isPrivate // may differ from 'isPrivate'
						,data: data
					})));
				
				resolve(Object.freeze({__proto__: null
					,isPrivate: !!t.isPrivate
					,tabs: t.tabs
				}));
			} catch (e) {
				reject(e + '');
			}});
		});
	};
	
	let _nonPrivateWindow, _privateWindow;
	const _onNonPrivateOpen = [], _onPrivateOpen = [];
	
	const groupContext = Object.freeze({
		__proto__: null
		,onQuit (f) {
			quitHandlers.push(f);
		}
		,closeAll () { // Please call after the script is terminated
			windowClosers.forEach(f => f());
			windowClosers.length = 0;
		}
		,showMessage (type, m) {
			messageSenders.forEach(f => f(type, m));
		}
		,openNonPrivate () {
			return new Promise((resolve, reject) => {
				if (_nonPrivateWindow) {
					resolve(_nonPrivateWindow);
				} else if (false === _nonPrivateWindow) {
					_onNonPrivateOpen.push(w => void(resolve(w)));
				} else {
					_nonPrivateWindow = false; // pending
					_openBrowserWindow().then(w => {
						_nonPrivateWindow = w;
						resolve(w);
						_onNonPrivateOpen.forEach(f => f(w));
						_onNonPrivateOpen.length = 0; // free memory
					});
				}
			});
		}
		,openPrivate () {
			return new Promise((resolve, reject) => {
				if (_privateWindow) {
					resolve(_privateWindow);
				} else if (false === _privateWindow) {
					_onPrivateOpen.push(w => void(resolve(w)));
				} else {
					_privateWindow = false; // pending
					_openBrowserWindow(true).then(w => {
						_privateWindow = w;
						resolve(w);
						_onPrivateOpen.forEach(f => f(w));
						_onPrivateOpen.length = 0; // free memory
					});
				}
			});
		}
	});
	
	return groupContext;
};


/* Exports */
exports.createControlGroup = createControlGroup;

// vim: ts=4 noet ai

